#pragma once
#include <iostream>
#include "log.hpp"
#include "err.hpp"
#include "sock.hpp"
#include "epoller.hpp"
#include "util.hpp"
#include <string>
#include <functional>
#include <unordered_map>
#include <assert.h>

namespace tcpserver_ns
{
    class Connection;
    class tcpServer;
    using func_t = std::function<void(Connection *)>;
    // using hander_t = std::function<void(const std::string &)>;

    class Connection
    {
    public:
        Connection(int sock) : _sock(sock)
        {
        }
        ~Connection()
        {
        }

        void Register(func_t recver, func_t sender, func_t excepter)
        {
            _recver = recver;
            _sender = sender;
            _excepter = excepter;
        }
        int _sock;
        std::string _inbuffer;
        std::string _outbuffer;

        func_t _recver;
        func_t _sender;
        func_t _excepter;

        tcpServer *_tsp; // ? 思考有什么用?
    };

    class TcpServer
    {
    public:
        TcpServer(func_t servers, uint16_t port = 20000) : _port(port), _revs(nullptr), _num(64), _servers(servers)
        {
        }

        void initServer()
        {
            // 创建套接字
            _sock.Socket();
            _sock.Bind(_port);
            _sock.Listen();
            // ET模式下需要fd 为非阻塞

            // 创建 epoll 模型
            _epoller.create();

            // 将目前唯一一个 _lisentsock 创建connection 添加到epoll模型中
            AddConnection(_sock.Fd(), EPOLLIN | EPOLLET, std::bind(&TcpServer::Accepter, this, std::placeholders::_1), nullptr, nullptr);

            _revs = new struct epoll_event[_num];
        }
        // 获取新链接

        // 事件派发器
        void Dispatcher()
        {
            while (true)
            {
                Loop(1000);
                // logMessage(DEBUG, "timeout>>>>");
            }
        }

        ~TcpServer()
        {
            if (_revs)
                delete[] _revs;
        }

    private:
        // 监听sock只关心读事件(accept),
        // 监听sock的读处理函数
        void Accepter(Connection *conn)
        {
            // std::cout << "accepter in" << std::endl;

            while (true) // 可能全连接队列里 不只有一个链接就绪, 所以需要循环接收链接
            {
                std::string clientip;
                uint16_t clientport;
                int err = 0;
                int sock = _sock.Accept(&clientip, &clientport, &err);
                if (sock > 0)
                {
                    // 合法的文件描述符号
                    Util::setNonBlock(sock); // 在epoll的ET模式中每个fd都是非阻塞
                    // 获取到一个链接 得到新的newsock
                    AddConnection(
                        sock, EPOLLIN | EPOLLET,
                        std::bind(&TcpServer::Recver, this, std::placeholders::_1),
                        std::bind(&TcpServer::Sender, this, std::placeholders::_1),
                        std::bind(&TcpServer::Excepter, this, std::placeholders::_1));
                    logMessage(DEBUG, "get a new link, info: %s:[%d]", clientip.c_str(), clientport);
                }
                else
                {
                    // 说明异常了
                    if (err == EAGAIN || err == EWOULDBLOCK) // 未出错, 只是非阻塞Io 没数据了
                        break;
                    else if (err == EINTR) // 系统调用被信号中断, 需要再次调用
                        continue;
                    else
                        break;
                }
            }

            // std::cout << "accepter out" << std::endl;
        }
        // 普通fd的读处理函数
        void Recver(Connection *conn)
        {
            logMessage(DEBUG, "Recver in");
            char buf[1024];
            while (true)
            {
                ssize_t n = recv(conn->_sock, buf, sizeof(buf) - 1, 0);
                // logMessage(DEBUG, "recv ret n : %d", n);
                if (n > 0)
                {
                    // 读取到数据
                    buf[n] = 0;
                    conn->_inbuffer += buf;
                }
                else if (n == 0)
                {
                    // 对方关闭写端文件描述符
                    if (conn->_excepter)
                    {
                        conn->_excepter(conn); // 调用异常
                    }
                    return;
                }
                else
                {
                    // n = -1;
                    if (errno == EAGAIN || errno == EWOULDBLOCK)
                    {
                        // 未读取到数据 数据读取完毕
                        // logMessage(DEBUG, "recv 未读取到数据 ret n : %d", n);
                        break;
                    }
                    else if (errno == EINTR)
                    {
                        continue;
                    }
                    else
                    {
                        // 真正出异常了
                        if (conn->_excepter)
                        {
                            conn->_excepter(conn); // 调用异常
                        }
                        return;
                    }
                }
            }
            _servers(conn); // 发送给上层, 尝试去提取

            // logMessage(DEBUG, "%d -> %s", conn->_sock, conn->_inbuffer.c_str());
            // 当前读取事件处理完成
            // 接下来是处理读到的数据
            //  std::string onepackage;
            //  while(ParseOnePackage(conn->_inbuffer, &onepackage)){
            //      //读取到了一个完整的报文 ->再向上交付
            //      _hander(onepackage);

            // }
        }
        // 普通fd的写处理函数
        void Sender(Connection *conn)
        {
            logMessage(DEBUG, "sender in");
            while (true)
            {
                ssize_t s = send(conn->_sock, conn->_outbuffer.c_str(), conn->_outbuffer.size(), 0);
                logMessage(DEBUG, "send ret %d",s);
                if (s > 0)
                {
                    conn->_outbuffer.erase(0, s);
                    // 发送成功
                    if (conn->_outbuffer.empty())
                    {
                        break;
                    }
                }
                else
                {
                    // s == -1
                    if (errno == EAGAIN || errno == EWOULDBLOCK)
                    {
                        // 发送缓冲区被写满了, 数据没发完
                        break;
                    }
                    else if (errno == EINTR)
                    {
                        // 被信号中断了
                        continue;
                    }
                    else
                    {
                        // 真的错了
                        logMessage(DEBUG, "****** errno:%d : %s", errno , strerror(errno));
                        if (conn->_excepter)
                        {
                            conn->_excepter(conn);
                            return;
                        }
                    }
                }
            } // end while

            // // 将对应的 EPOLLOUT事件注册进入epoll模型中
            if (conn->_outbuffer.empty())
            {
                return;
            }
            else
            {
                _epoller.control(conn->_sock, EPOLLIN | EPOLLOUT | EPOLLET, EPOLL_CTL_MOD);
            }
        }

        // 普通fd的异常处理函数
        void Excepter(Connection *conn)
        {
            logMessage(DEBUG, "Excepter hander in");
            // 这个链接出异常了, 怎么办?删掉这个链接并且释放掉对应的资源
            // 1. 从 _connections 里面去掉
            _connections.erase(conn->_sock);

            // 2.从epoll模型中去掉
            _epoller.control(conn->_sock, 0, EPOLL_CTL_DEL);

            // close关闭文件描述符
            close(conn->_sock);

            delete conn;
        }
        
        void AddConnection(int sock, uint32_t events, func_t recver, func_t sender, func_t excepter)
        {
            // 1.首先为sock创建,connection, 并且初始化, 并添加到_connections
            // 如果event设置为EPOLLET模式, 需要将对应的fd设置为非阻塞
            if (events & EPOLLET)
            {
                Util::setNonBlock(_sock.Fd());
            }
            Connection *conn = new Connection(sock);
            // 给对应的sock设置对应的回调方法
            conn->Register(recver, sender, excepter);

            // 2.其次将sock与他要关心的事件"写透式" 注册到epoll中, 让epoll帮我们关心
            bool r = _epoller.addEvent(sock, events);
            assert(r);

            // 2.将KV 添加到_connections
            _connections.insert(std::pair<int, Connection *>(sock, conn));
        }

        void Loop(int timeout)
        {
            int n = _epoller.Wait(_revs, _num, timeout);
            for (int i = 0; i < n; i++)
            {
                int sock = _revs[i].data.fd;
                uint32_t events = _revs[i].events;

                if (isConnectionExists(sock) && events & EPOLLERR)
                {
                    // 异常了
                    events |= (EPOLLIN | EPOLLOUT); // 将异常事件 转化为读写事件 在读写的时候做异常处理
                }
                if (isConnectionExists(sock) && events & EPOLLHUP)
                {
                    // 发生了挂起事件
                    events |= (EPOLLIN | EPOLLOUT); // 将挂起事件 转化为读写事件 在读写的时候做异常处理
                }

                // 判读 sock有, 事件有, 绑定了对应的事件回调函数有 ,三次判读
                if (isConnectionExists(sock) && (events & EPOLLIN))
                {
                    // 读事件
                    if (_connections[sock]->_recver)
                        _connections[sock]->_recver(_connections[sock]); // 不同的fd对应不同的connection 不同的connection里面注册有不同的读事件处理函数
                }
                if (isConnectionExists(sock) && events & EPOLLOUT)
                {
                    // 写事件
                    if (_connections[sock]->_sender)
                        _connections[sock]->_sender(_connections[sock]); /// 不同的fd对应不同的connection 不同的connection里面注册有不同的写事件处理函数
                }
            }
        }

        // 判读sock是否在 _connections 中
        bool isConnectionExists(int sock)
        {
            auto it = _connections.find(sock);
            return it != _connections.end();
        }

    private:
        uint16_t _port;
        Sock _sock;
        Epoller _epoller;

        std::unordered_map<int, Connection *> _connections;

        struct epoll_event *_revs;
        int _num;
        // hander_t _hander;
        func_t _servers;
    };
}